Voxel Mosaics 2¶
Choose axial (A), coronal (C) or sagittal (S) slices. Modify with cross slices (X) and renderings (R).
See https://niivue.com/demos/features/mosaics2.html for mirror.
In [1]:
from pathlib import Path
from ipyniivue import download_dataset
BASE_API_URL = "https://niivue.com/demos/images/"
DATA_FOLDER = Path("images")
# Download data for example
download_dataset(
BASE_API_URL,
DATA_FOLDER,
files=[
"fslmean.nii.gz",
"fslt.nii.gz",
],
)
fslmean.nii.gz already exists. fslt.nii.gz already exists. Dataset downloaded successfully to images.
In [2]:
import ipywidgets as widgets
from IPython.display import display
from ipyniivue import NiiVue
## Create NiiVue Instance and Load Data
nv = NiiVue(height=600, back_color=(1, 1, 1, 1), is_colorbar=True, drag_mode="CONTRAST")
nv.load_volumes(
[
{
"path": DATA_FOLDER / "fslmean.nii.gz",
"colormap": "gray",
"colorbar_visible": False,
},
{
"path": DATA_FOLDER / "fslt.nii.gz",
"colormap": "warm",
"colormap_negative": "winter",
"cal_min": 1,
"cal_max": 6,
},
]
)
initial_mosaic = (
"A 0 L+ 50 L- 60 C -10 0 S 40; A X 0 S X 0 C X 0 R A X 0 R S X 0 R C X 0"
)
nv.set_slice_mosaic_string(initial_mosaic)
## Create Interactive Controls
# mosaic string input
mosaic_text = widgets.Text(
value=initial_mosaic,
placeholder="Enter mosaic string",
description="Mosaic string:",
style={"description_width": "initial"},
layout=widgets.Layout(width="70%"),
)
# help button
help_button = widgets.Button(
description="Help",
button_style="info",
tooltip="Click for information about mosaic strings",
layout=widgets.Layout(width="80px"),
)
# radiological convention checkbox
radio_check = widgets.Checkbox(value=False, description="Radiological", indent=False)
# world space checkbox
mm_check = widgets.Checkbox(value=False, description="World space", indent=False)
# ruler checkbox
ruler_check = widgets.Checkbox(value=False, description="Ruler", indent=False)
# nose left checkbox
sag_check = widgets.Checkbox(value=False, description="Nose left", indent=False)
# colorbar checkbox
colorbar_check = widgets.Checkbox(value=True, description="Colorbar", indent=False)
# negative colors checkbox
negative_check = widgets.Checkbox(
value=True, description="Negative colors", indent=False
)
# orient cube checkbox
cube_check = widgets.Checkbox(value=False, description="Cube", indent=False)
# high DPI checkbox
dpi_check = widgets.Checkbox(value=True, description="HighDPI", indent=False)
# gamma slider
gamma_slider = widgets.FloatSlider(
value=1.0, min=0.1, max=2.0, step=0.1, description="Gamma:", continuous_update=True
)
# drag mode dropdown
drag_mode = widgets.Dropdown(
options=[
("none", 0),
("contrast", 1),
("measurement", 2),
],
value=1,
description="Drag mode:",
style={"description_width": "initial"},
)
# output for messages
output = widgets.Output()
## Setup Event Handlers
def on_mosaic_change(change):
"""Handle mosaic string changes."""
nv.set_slice_mosaic_string(change["new"])
def on_help_click(b):
"""Display help information."""
with output:
output.clear_output()
print("Mosaic String Help:")
print("=" * 50)
print("Choose axial (A), coronal (C) or sagittal (S) slices.")
print("Modify with cross slices (X) and renderings (R).")
print("\nExample patterns:")
print(" A 0 20 40 - Axial slices at positions 0, 20, 40")
print(" C -10 0 10 - Coronal slices at positions -10, 0, 10")
print(" S 0 - Sagittal slice at position 0")
print(" A X 0 - Axial slice with cross at position 0")
print(" R - 3D rendering")
print(" L+ 50 - Left hemisphere at position 50")
print(" L- 60 - Right hemisphere at position 60")
def on_radio_change(change):
"""Handle radiological convention toggle."""
nv.set_radiological_convention(change["new"])
def on_mm_change(change):
"""Handle world space toggle."""
nv.set_slice_mm(change["new"])
def on_ruler_change(change):
"""Handle ruler toggle."""
nv.opts.is_ruler = change["new"]
def on_sag_change(change):
"""Handle sagittal nose left toggle."""
nv.opts.sagittal_nose_left = change["new"]
def on_colorbar_change(change):
"""Handle colorbar toggle."""
nv.opts.is_colorbar = change["new"]
def on_negative_change(change):
"""Handle negative colormap toggle."""
if change["new"]:
nv.set_colormap_negative(nv.volumes[1].id, "winter")
else:
nv.set_colormap_negative(nv.volumes[1].id, "")
def on_cube_change(change):
"""Handle orient cube toggle."""
nv.opts.is_orient_cube = change["new"]
def on_dpi_change(change):
"""Handle high DPI toggle."""
nv.set_high_resolution_capable(change["new"])
def on_gamma_change(change):
"""Handle gamma adjustment."""
nv.set_gamma(change["new"])
def on_drag_mode_change(change):
"""Handle drag mode change."""
nv.opts.drag_mode = change["new"]
# attach event handlers
mosaic_text.observe(on_mosaic_change, names="value")
help_button.on_click(on_help_click)
radio_check.observe(on_radio_change, names="value")
mm_check.observe(on_mm_change, names="value")
ruler_check.observe(on_ruler_change, names="value")
sag_check.observe(on_sag_change, names="value")
colorbar_check.observe(on_colorbar_change, names="value")
negative_check.observe(on_negative_change, names="value")
cube_check.observe(on_cube_change, names="value")
dpi_check.observe(on_dpi_change, names="value")
gamma_slider.observe(on_gamma_change, names="value")
drag_mode.observe(on_drag_mode_change, names="value")
## Display All
# organize controls
mosaic_row = widgets.HBox([mosaic_text, help_button])
checkbox_row1 = widgets.HBox([radio_check, mm_check, ruler_check, sag_check])
checkbox_row2 = widgets.HBox([colorbar_check, negative_check, cube_check, dpi_check])
slider_row = widgets.HBox([gamma_slider, drag_mode])
# create main layout
controls = widgets.VBox([mosaic_row, checkbox_row1, checkbox_row2, slider_row, output])
# display everything
display(widgets.VBox([controls, nv]))